; bytecode is tight, but slow.
; one way to utilize it better is to stagger processing
;  for instance only execute x events per frame,
;  or all events on even frames, and entity logic on other frames.  this isn't an action game.

;Virtual Machine Registers
;data stack     6502 stack
;RSP            zp pointer
;IPBASE         zp pointer
;A              zp pointer
;IP             Y, offset from (IBASE)
;TOS            in stack @ 101,SP (what the file is named after)
;A and X are free

IFNDEF VM_BTM
	VM_BTM =$00
	VM_TOP =$20
ENDIF

ENUM VM_BTM
	VM_RSP:  .db 0	  ; 8-bit return stack pointer
	VM_TEMP: .db 0    ; work variable
	VM_A:    .dw 0
	VM_IPBASE:  .dw 0
	VM_SPTMP:.db 0
	VM_RTOP =VM_TOP   ; grows downward.
ENDE




macro ifetch
	lda   (VM_IPBASE),y
	iny
endm

; * v * ====== THE INTERPRETER ====== ^ _ ~

; entry point!   simply put db statements under a JSR to this.
bytecode:
	tsx
	inx
	inx
	stx   VM_SPTMP
	pla
	sta   VM_IPBASE
	pla
	sta   VM_IPBASE+1
	ldy   #1         ; compensate for return address being 1 byte behind
interpret:   ;VM_IPBASE = address of code, Y = offset
	ldx   #VM_RTOP   ; initialize RSP
	stx   VM_RSP
_vmnext:   ;31   estimate ~600 virtual ops per frame
	ifetch
	tax
	lda   opcodes+1, x
	pha
	lda   opcodes, x
	pha
	rts

_end:	     ; use to get out of interpreter  (return and data stack irrelevant!)
	ldx   VM_SPTMP
	txs
	rts

macro vmnext
;	jmp _vmnext   ; uncomment this and comment out the rest to save a few hundred bytes at the expense of cpu
	ifetch
	tax
	lda   opcodes+1, x
	pha
	lda   opcodes, x
	pha
	rts
endm



;subroutines
;call
; push IPBASE and Y onto RS
; get new IPBASE and set Y to 0
; jump to interpret
;ret
; POP IPBASE and Y from RS
; jump to interpret

_call:
	ldx VM_RSP
	dex
	dex
	dex
 	;txa     ;\
 	;.db $cb,3;sbx #3  ;saves 2 cycles
	stx VM_RSP

	lda VM_IPBASE
	sta 1,x
	lda VM_IPBASE+1
 	sta 2,x

	ifetch
 	pha
	;.db $b3,VM_IPBASE ;lax   (VM_IPBASE),y  ;saves 2 cycles and 1 byte
	ifetch
	; have to do these after fetching the bytes or we'd screw up the 2nd fetch!
	sta VM_IPBASE+1
	pla
	sta VM_IPBASE
 	sty 0,x
 	ldy #0
	vmnext

_exit:
	ldx VM_RSP
	lda 1,x
	sta VM_IPBASE
	lda 2,x
	sta VM_IPBASE+1

	ldy 0,x
	inx
	inx
	inx
	stx VM_RSP
	vmnext

include bytecode_core_s.s


